package com.imooc.mq;

import com.imooc.api.mq.RabbitMQSMSConfig;
import com.imooc.pojo.mq.SMSContentQO;
import com.imooc.utils.GsonUtils;
import com.imooc.utils.SMSUtils;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @version 1.0
 * @Author Mr.Yang
 * @Date 2024-08-20 19:20
 * @question: 短信监听消费者
 */

@Slf4j
@Component
public class RabbitMQSMSConsumer {

    @Autowired
    private SMSUtils smsUtils;

//    /**
//     * 监听队列,并且处理消息
//     * @param payload
//     * @param message
//     */
//    @RabbitListener(queues = {RabbitMQSMSConfig.SMS_QUEUE})
//    public void watchQueue(String payload, Message message) throws Exception {
//
//        //获得routingKey
//        String routingKey = message.getMessageProperties().getReceivedRoutingKey();
//        log.info("routingKey = " + routingKey);
//
//        String msg = payload;
//        log.info("msg = " + msg);
//
//        if (routingKey.equalsIgnoreCase(RabbitMQSMSConfig.ROUTING_KEY_SMS_SEND_LOGIN)) {
//            //此处为短信发送的消息消费处理
//            SMSContentQO contentQO = GsonUtils.stringToBean(msg, SMSContentQO.class);
//            String mobile = contentQO.getMobile();
//            String content = contentQO.getContent();
//            log.info("手机号 = " + mobile);
//            log.info("验证码 = " + content);
////            smsUtils.sendSMS(contentQO.getMobile(), contentQO.getContent());
//        }
//    }

    //设置最大的重试次数为3次
    private static final int MAX_RETRIES = 3;
    //记录重试次数的MAP集合
    private Map<Long, Integer> retryCounts = new ConcurrentHashMap<>();

    /**
     * 监听队列,并且处理消息
     * @param message
     * @param channel
     * @throws Exception
     */
    @RabbitListener(queues = {RabbitMQSMSConfig.SMS_QUEUE})
    public void watchQueue(Message message, Channel channel) throws Exception {

        //获取标签
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        int retryCount = retryCounts.getOrDefault(deliveryTag, 0);

        try {

            String routingKey = message.getMessageProperties().getReceivedRoutingKey();
            log.info("routingKey = " + routingKey);

//            int a = 1/0;

            String msg = new String(message.getBody());
            log.info("msg = " + msg);

//            channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);

            if (routingKey.equalsIgnoreCase(RabbitMQSMSConfig.ROUTING_KEY_SMS_SEND_LOGIN)) {
                //此处为短信发送的消息消费处理
                SMSContentQO contentQO = GsonUtils.stringToBean(msg, SMSContentQO.class);
                String mobile = contentQO.getMobile();
                String content = contentQO.getContent();
                log.info("手机号 = " + mobile);
                log.info("验证码 = " + content);
//                smsUtils.sendSMS(contentQO.getMobile(), contentQO.getContent());

                /**
                 * 如果消息处理成功,则确认消息
                 * 手动ack确认
                 * deliveryTag: 消息投递的标签
                 * multiple: 1.当multiple设置为false时,表示仅确认deliveryTag所标识的那一条消息,适用于每次只处理并确认一条消息的场景
                 *              2.当multiple设置为true时,表示确认deliveryTag及其之前(但不包括deliveryTag + 1)的所有未确认的消息
                 *
                 */
                channel.basicAck(deliveryTag, false);
                retryCounts.remove(deliveryTag); //移除成功的重试计数
            }
        } catch (Exception e) {
            e.printStackTrace();

            retryCounts.put(deliveryTag, retryCount + 1); //增加重试计数

            if (retryCount < MAX_RETRIES) {
                //TODO 可以在这里设置重试延迟,但RabbitMQ原生不支持,需要消费者自己实现
                //例如,可以记录一个时间戳,并在下次消费前检查时间差
                /**
                 * 第三个参数 ---->>> requeue : true 重回队列 ; false 丢弃消息
                 */
                channel.basicNack(deliveryTag, false, true);
            } else {
                //达到最大重试次数,记录到数据库并丢弃消息
                log.error("Max retries reached for message with deliveryTag: " + deliveryTag);
                storeMessageToDatabase(message);
                channel.basicNack(deliveryTag, false, false);
            }
            //不能直接抛出丢弃消息
//            channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,false);
//            channel.basicReject();
        }
    }

    /**
     * TODO 存储到数据库的方法
     * @param message 消息体
     */
    private void storeMessageToDatabase(Message message) {
        //标签
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        //routingKey
        String receivedRoutingKey = message.getMessageProperties().getReceivedRoutingKey();
        //消息数据
        String msg = new String(message.getBody());

        log.info("保存到数据库成功~ ！");
    }


}

